//-----------------------------------------------------------------------
// <copyright file="Changes.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// </copyright>
// <summary>This task does the difference of local copy and VSS and tell if anny file have been modified</summary>
//-----------------------------------------------------------------------
namespace Microsoft.Sdc.Tasks.SourceSafe
{
    using System;
    using System.Globalization;
    using System.IO;
    using Microsoft.Win32;
    using Microsoft.Sdc.Tasks.Configuration;
    using Microsoft.Build.Framework;

    /// <summary>
    /// This task does the difference of local copy and VSS and tell if anny file have been modified.
    /// </summary>
    /// <remarks>
    /// <code><![CDATA[
    /// <SourceSafe.Changes PathDiff="path"
    ///             Database="database"
    ///             Username="username" 
    ///             Password="password"
    ///             SSVersion="ssversion"
    /// />]]></code>
    /// <para>where:</para>
    /// <para><i>path (Required)</i></para>
    /// <para>The full path to the file or folder.</para>
    /// <para><i>database</i></para>
    /// <para>The VSS database location. This database must exist and must be a valid VSS database.</para>
    /// <para><i>username</i></para>
    /// <para>The username that will be used when labelling VSS</para>
    /// <para><i>password</i></para>
    /// <para>The password for the username specified in <i>username</i></para>
    /// <para><i>ssversion</i></para>
    /// <para>The SourceSafe version to use. Default is 6d. Supports 6d and 2005</para>
    /// </remarks>
    /// <example>
    /// <code><![CDATA[
    /// <Project>
    ///     <Target Name="Test" >
    ///         <SourceSafe.Changes
    ///             Database="database"
    ///             Username="username" 
    ///             Password="password" 
    ///             PathDiff="hum.c">
    ///             <Output TaskParameter="ChangesFound" PropertyName="Found" />
    ///         </SourceSafe.Changes>
    ///     </Target>
    /// </Project>
    /// ]]></code>    
    /// </example>
    public class Changes : TaskBase
    {
        private bool changesFound;
        private string project;
        private string database;
        private string username;
        private string password;
        private string workingDirectory;
        private string ssafeVersion = "6d";
        private ShellExecute shellExecute;
        private string pathDiff;

        public string PathDiff
        {
            get { return this.pathDiff; }
            set { this.pathDiff = value; }
        }

        /// <summary>
        /// Gets or sets the SourceSafe version.
        /// </summary>
        /// <value>The SS version.</value>
        public string SSVersion
        {
            get { return this.ssafeVersion; }
            set { this.ssafeVersion = value; }
        }

        [Output]
        public bool ChangesFound
        {
            get { return this.changesFound; }
            set { this.changesFound = value; }
        }

        public string Project
        {
            get { return (this.project ?? String.Empty); }
            set { this.project = value; }
        }

        public string Database
        {
            get { return (this.database ?? String.Empty); }
            set { this.database = value; }
        }

        public string Username
        {
            get { return (this.username ?? String.Empty); }
            set { this.username = value; }
        }

        public string Password
        {
            get { return (this.password ?? String.Empty); }
            set { this.password = value; }
        }

        public string WorkingDirectory
        {
            get { return (this.workingDirectory ?? String.Empty); }
            set { this.workingDirectory = value; }
        }

        /// <summary>
        /// Performs the action of this task.
        /// </summary>
        protected override void InternalExecute()
        {
            if (this.GetVersionInformation() == false)
            {
                return;
            }

            string outputPath = Environment.CurrentDirectory + "\\Output\\VSSDiff.txt";
            if (File.Exists(outputPath))
            {
                File.Delete(outputPath);
            }

            string args = String.Format(CultureInfo.InvariantCulture, "Diff \"{0}\" -O@\"{1}\\VSSDiff.txt\"", this.PathDiff, Path.Combine(Environment.CurrentDirectory, "Output"));
            Environment.CurrentDirectory = this.WorkingDirectory;
            Log.LogMessage(MessageImportance.Low, string.Format("Executing: {0} {1}", this.shellExecute.Filename, args));
            this.shellExecute.Arguments = args;
            this.shellExecute.Execute();
            if (string.IsNullOrEmpty(this.shellExecute.StandardOutput.Trim()) == false)
            {
                Log.LogMessage(this.shellExecute.StandardOutput);
            }

            if (string.IsNullOrEmpty(this.shellExecute.StandardError.Trim()) == false)
            {
                Log.LogMessage(this.shellExecute.StandardError);
            }

            using (FileStream fs = new FileStream(outputPath, FileMode.OpenOrCreate, FileAccess.Read))
            using (StreamReader sr = new StreamReader(fs))
            {
                this.ChangesFound = true;
                while (!sr.EndOfStream)
                {
                    string str = sr.ReadLine();
                    if (str.Contains("No differences"))
                    {
                        this.ChangesFound = false;
                        break;
                    }
                }

                sr.Close();
                fs.Close();
            }
        }

        private bool GetVersionInformation()
        {
            RegistryKey vssKey;
            this.shellExecute = new ShellExecute();
            switch (this.SSVersion)
            {
                case "6d":
                    vssKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\VisualStudio\6.0\Setup\Microsoft Visual SourceSafe Server");
                    if (vssKey == null)
                    {
                        // couldn't find the Server key so try the other one
                        vssKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\VisualStudio\6.0\Setup\Microsoft Visual SourceSafe");
                    }

                    if (vssKey != null)
                    {
                        string pathToSourceSafe = Convert.ToString(vssKey.GetValue("ProductDir"), CultureInfo.InvariantCulture);
                        this.shellExecute.Filename = Path.Combine(pathToSourceSafe, @"win32\ss.exe");
                        vssKey.Close();
                    }
                    else
                    {
                        Log.LogMessage(MessageImportance.Low, string.Format("Version is 6d but registry keys not found at: {0} or {1}. Assuming ss.exe is in the Path", @"SOFTWARE\Microsoft\VisualStudio\6.0\Setup\Microsoft Visual SourceSafe Server", @"SOFTWARE\Microsoft\VisualStudio\6.0\Setup\Microsoft Visual SourceSafe"));
                        this.shellExecute.Filename = "ss.exe";
                    }

                    break;
                case "2005":
                    vssKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\VisualStudio\8.0\Setup\VS\VSS");

                    if (vssKey != null)
                    {
                        string pathToSourceSafe = Convert.ToString(vssKey.GetValue("ProductDir"), CultureInfo.InvariantCulture);
                        this.shellExecute.Filename = Path.Combine(pathToSourceSafe, "ss.exe");
                        vssKey.Close();
                    }
                    else
                    {
                        Log.LogMessage(MessageImportance.Low, string.Format("Version is 2005 but registry key not found at: {0}. Assuming ss.exe is in the Path", @"SOFTWARE\Microsoft\VisualStudio\8.0\Setup\VS\VSS"));
                        this.shellExecute.Filename = "ss.exe";
                    }

                    break;
                default:
                    Log.LogError("Invalid SSVersion. Valid options are 6d or 2005");
                    return false;
            }

            this.shellExecute.EnvironmentVariables["SSDIR"] = this.Database;
            if (string.IsNullOrEmpty(this.Username))
            {
                this.Username = Environment.UserName;
            }

            this.shellExecute.EnvironmentVariables["SSUSER"] = this.Username;
            if (string.IsNullOrEmpty(this.Password) == false)
            {
                this.shellExecute.EnvironmentVariables["SSPWD"] = this.Password;
            }

            Log.LogMessage(MessageImportance.Low, string.Format("Using UserName: {0} and Password: {1}", this.username, this.Password));
            return true;
        }
    }
}